package com.erdos.common.web.tag;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ComboTag extends TagSupport {
	
	private static final long serialVersionUID = -5614198079885297156L;

	private static final Log logger = LogFactory.getLog(ComboTag.class);
	
	/** Target div id for DHTMLX Combo component to bind */
	private String target;
	
	/** 
	 * The name of DHTMLX Combo component for two purposes: 
	 * 1. used in form
	 * 2. used as the handler of the return value by "new dhtmlXCombo("divid","mycombo",100)"
	 */
	private String name;
	
	/** DHTMLX Combo component readonly property */
	private String readonly;
	
	/** The selected option index of DHTMLX Combo component, based on 0 */
	private String selectedValue;
	
	private String showAll;
	
	/** DHTMLX Combo component width for show */
	private String width;
	
	/**
	 * A map structure stores the init options,
	 * in Map: <key, value>
	 * in Combo: [value,lable=key]
	 */
	private String options;

	private String value;

	private String lable;

	public String getTarget() {
		return target;
	}

	public void setTarget(String target) {
		this.target = target;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getReadonly() {
		return readonly;
	}

	public void setReadonly(String readonly) {
		this.readonly = readonly;
	}

	public String getSelectedValue() {
		return selectedValue;
	}

	public void setSelectedValue(String selectedValue) {
		this.selectedValue = selectedValue;
	}

	public String getWidth() {
		return width;
	}

	public void setWidth(String width) {
		this.width = width;
	}

	public String getOptions() {
		return options;
	}

	public void setOptions(String options) {
		this.options = options;
	}
	
	@Override
	public int doStartTag() throws JspException {
		try {
			outputDiv();
			outputCombo();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return EVAL_PAGE;// super.doStartTag();
	}
	
	private void outputDiv() throws IOException {
		JspWriter out = pageContext.getOut();
		StringBuffer div = new StringBuffer();
		div.append("<div id=\"").append(this.target).append("\"");
		div.append(" ");
		div.append("name=\"").append(this.target).append("name\"");
		div.append("/>");
		out.println(div.toString());
	}
	
	private void outputCombo() throws Exception {
		if (Integer.parseInt(this.width) < 1) {
			this.width = "100";
		}
		JspWriter out = pageContext.getOut();
		StringBuffer combo = new StringBuffer();
		combo.append("<script> ");
		combo.append("var ").append(name)
			.append("=new dhtmlXCombo(\"").append(this.target).append("\",")
			.append("\"").append(this.name).append("\",").append(this.width).append(");");
		if (!"false".equalsIgnoreCase(this.readonly)) {
			combo.append(this.name).append(".readonly(true);");
		}
		if (!"false".equalsIgnoreCase(this.showAll)) {
			combo.append(this.name)
			.append(".addOption([[\"\",\"").append("--all--").append("\"]]);");
		}
		if ((this.options != null) && (this.options.length() > 0)) {
			HttpServletRequest request =
				(HttpServletRequest) pageContext.getRequest();
			Object objs = request.getAttribute(this.options);
			if (objs instanceof Map) {
				Map<String, String> optionMap = (Map<String, String>) objs;
				for (Map.Entry<String, String> entry : optionMap.entrySet()) {
					combo.append(this.name)
						.append(".addOption([[\"")
						.append(entry.getKey()).append("\",\"").append(entry.getValue())
						.append("\"]]);");
				}
			}else if (objs instanceof Collection) {
				if ((this.value == null)
						|| (this.lable ==null)
						|| (this.value.length() == 0)
						|| (this.lable.length() == 0)) {
					throw new Exception("Illegal taglib property."); 
				}
				Collection optionCollection = (Collection) objs;
				for (Object obj : optionCollection) {
					combo.append(this.name)
						.append(".addOption([[\"")
						.append(getTargetFieldValue(obj, this.value))
						.append("\",\"").append(getTargetFieldValue(obj, this.lable))
						.append("\"]]);");
				}
			} else {
				throw new Exception("Illegal type."); 
			}
			if ((this.selectedValue != null) && (this.selectedValue.length() != 0)) {
				combo.append(this.name)	.append(".selectOption(")
					.append(this.name).append(".getIndexByValue(\'")
					.append(this.selectedValue).append("\'));");
			}
		}
		combo.append(" </script>");
		out.println(combo.toString());
	}
	private String getTargetFieldValue(Object owner, String targetField)
	throws Exception {
		Class ownerClass = owner.getClass();
		StringBuffer methodName = new StringBuffer();
		methodName.append("get")
			.append(targetField.substring(0, 1).toUpperCase())
			.append(targetField.substring(1));
		Method method = ownerClass.getMethod(methodName.toString(), null);
		return method.invoke(owner, null).toString();
	}

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}

	public String getLable() {
		return lable;
	}

	public void setLable(String lable) {
		this.lable = lable;
	}

	public String getShowAll() {
		return showAll;
	}

	public void setShowAll(String showAll) {
		this.showAll = showAll;
	}

}
